package com.way.compass;

import android.app.Activity;
import android.content.Context;
import android.graphics.drawable.AnimationDrawable;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.view.animation.AccelerateInterpolator;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.baidu.location.BDLocation;
import com.baidu.location.BDLocationListener;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;

/**
 * 主Activity
 * 
 * @author way
 * 
 */
public class CompassActivity extends Activity {
	private static final int EXIT_TIME = 3000;// 两次按返回键的间隔判断
	private final float MAX_ROATE_DEGREE = 1.0f;// 最多旋转一周，即360°
	private SensorManager mSensorManager;// 传感器管理对象
	private Sensor mOrientationSensor;// 方向传感器
	private Sensor mPressureSensor;// 气压传感器
	private Sensor mTemperatureSensor;// 温度传感器
	private float mDirection;// 当前方向值
	private float mTargetDirection;// 目标方向值，即需要旋转到的方向
	private AccelerateInterpolator mInterpolator;// 动画从开始到结束，变化率是一个加速的过程,就是一个动画速率
	protected final Handler mHandler = new Handler();
	private boolean mStopDrawing;// 是否停止指南针旋转的标志位
	private long firstExitTime = 0L;// 用来保存第一次按返回键的时间
	private LocationClient mLocationClient = null;//百度定位

	private CompassView mPointer;// 指南针旋转指针
	private CompassView mCompassValues;//指南针旋转表盘
	private TextView mDirectionTV;//顶部显示方向
	
	private TextView mLatitudeTV;// 纬度
	private TextView mLongitudeTV;// 经度
	private TextView mPressureTV;// 气压
	private TextView mAltitudeTV;// 海拔
	
	private LinearLayout mAngleLayout;// 显示方向度数的容器
	private ImageView mGuideAnimation;//引导用户校准指南针的动画
	private TextView mGuideTV;//引导用户校准指南针的提示
	private LinearLayout mBottomUnit;//底部单元
	private TextView mAddressTV;//显示定位地址
	private ImageView mPressureShow;//显示气压进度
	private ImageView mAltitudeShow;//显示海拔进度
	private boolean isNeedAccuracy;

	protected Runnable stopGuideAnimTask = new Runnable() {

		@Override
		public void run() {
			mGuideTV.setVisibility(View.GONE);
			mGuideAnimation.setVisibility(View.GONE);
			mAngleLayout.setVisibility(View.VISIBLE);
		}
	};
	protected Runnable startGuideAnimTask = new Runnable() {

		@Override
		public void run() {
			mGuideAnimation.setVisibility(View.VISIBLE);
			((AnimationDrawable) mGuideAnimation.getDrawable()).start();
			mGuideTV.setVisibility(View.VISIBLE);
			mAngleLayout.setVisibility(View.GONE);

		}
	};

	// 更新指南针旋转的任务，
	protected Runnable mCompassViewUpdater = new Runnable() {
		@Override
		public void run() {
			if (mPointer != null && !mStopDrawing) {
				isNeedAccuracy = false;
				if (mDirection != mTargetDirection) {

					// calculate the short routine
					float to = mTargetDirection;
					if (to - mDirection > 180) {
						to -= 360;
					} else if (to - mDirection < -180) {
						to += 360;
					}

					// limit the max speed to MAX_ROTATE_DEGREE
					float distance = to - mDirection;
					if (Math.abs(distance) > MAX_ROATE_DEGREE) {
						distance = distance > 0 ? MAX_ROATE_DEGREE
								: (-1.0f * MAX_ROATE_DEGREE);
					}

					// need to slow down if the distance is short
					mDirection = normalizeDegree(mDirection
							+ ((to - mDirection) * mInterpolator
									.getInterpolation(Math.abs(distance) > MAX_ROATE_DEGREE ? 0.4f
											: 0.3f)));// 用了一个加速动画去旋转图片，很细致
					mPointer.updateDirection(mDirection);// 更新指南针旋转
					mCompassValues.updateDirection(mDirection);
				}

				updateDirection();// 更新方向值

				mHandler.postDelayed(mCompassViewUpdater, 20);// 20毫米后重新执行自己，比定时器好
			}
		}
	};

	private LocationClientOption getLocationClientOption() {
		LocationClientOption option = new LocationClientOption();
		option.setOpenGps(true);
		option.setAddrType("all");
		option.setServiceName(this.getPackageName());
		option.setScanSpan(0);
		option.disableCache(true);
		return option;
	}

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		isNeedAccuracy = true;
		mLocationClient = new LocationClient(this, getLocationClientOption());
		mLocationClient.registerLocationListener(mLocationListener);
		setContentView(R.layout.main);
		initServices();// 初始化传感器和位置服务
		initResources();// 初始化view

	}

	@Override
	public void onBackPressed() {// 按返回键退出应用
		long curTime = System.currentTimeMillis();
		if (curTime - firstExitTime < EXIT_TIME) {// 两次按返回键的时间小于2秒就退出应用
			finish();
		} else {
			Toast.makeText(this, R.string.exit_toast, Toast.LENGTH_SHORT)
					.show();
			firstExitTime = curTime;
		}
	}

	@Override
	protected void onResume() {
		super.onResume();

		if (mOrientationSensor != null) {
			Log.i("lwp", mOrientationSensor.toString());
			mSensorManager.registerListener(mOrientationSensorEventListener,
					mOrientationSensor, SensorManager.SENSOR_DELAY_GAME);
		}
		mStopDrawing = false;
		if (mPressureSensor != null)
			mSensorManager.registerListener(mSensorEventListener,
					mPressureSensor, SensorManager.SENSOR_DELAY_GAME);
		if (mTemperatureSensor != null)
			mSensorManager.registerListener(mSensorEventListener,
					mTemperatureSensor, SensorManager.SENSOR_DELAY_GAME);
		if (mLocationClient != null && !mLocationClient.isStarted())
			mLocationClient.start();
	}

	@Override
	protected void onPause() {
		super.onPause();
		mStopDrawing = true;
		if (mOrientationSensor != null) {
			mSensorManager.unregisterListener(mOrientationSensorEventListener);
		}
		if (mLocationClient != null && mLocationClient.isStarted())
			mLocationClient.stop();
		if (mPressureSensor != null || mTemperatureSensor != null)
			mSensorManager.unregisterListener(mSensorEventListener);
	}

	// 初始化view
	private void initResources() {
		mDirectionTV = (TextView) findViewById(R.id.layout_direction);
		mGuideAnimation = (ImageView) findViewById(R.id.guide_animation);
		mGuideAnimation.setVisibility(View.GONE);
		mGuideTV = (TextView) findViewById(R.id.guide_toast);
		mGuideTV.setVisibility(View.GONE);
		mAddressTV = (TextView) findViewById(R.id.address);
		mDirection = 0.0f;// 初始化起始方向
		mTargetDirection = 0.0f;// 初始化目标方向
		mInterpolator = new AccelerateInterpolator();// 实例化加速动画对象
		mStopDrawing = true;

		mPointer = (CompassView) findViewById(R.id.compass_pointer);// 自定义的指南针view
		mCompassValues = (CompassView) findViewById(R.id.compass_values);
		mLongitudeTV = (TextView) findViewById(R.id.textview_location_longitude_degree);
		mLatitudeTV = (TextView) findViewById(R.id.textview_location_latitude_degree);
		mPressureTV = (TextView) findViewById(R.id.textview_pressure);
		mAltitudeTV = (TextView) findViewById(R.id.textview_altitude);
		mAngleLayout = (LinearLayout) findViewById(R.id.layout_angle);// 顶部显示方向具体度数的LinearLayout
		
		mBottomUnit = (LinearLayout) findViewById(R.id.bottom_unit);
		mPressureShow = (ImageView) findViewById(R.id.pressure_show);
		mAltitudeShow = (ImageView) findViewById(R.id.altitude_show);
		if (mPressureSensor == null) {// 只要无气压传感器，就隐藏海拔和气压相关UI
			mBottomUnit.setBackgroundResource(R.drawable.background_bottom_2);
			mPressureShow.setVisibility(View.GONE);
			mAltitudeShow.setVisibility(View.GONE);
			findViewById(R.id.bottom_unit_pressure).setVisibility(View.GONE);
			findViewById(R.id.bottom_unit_altitude).setVisibility(View.GONE);
		}
	}

	// 初始化传感器和位置服务
	private void initServices() {
		// sensor manager
		mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
		mOrientationSensor = mSensorManager
				.getDefaultSensor(Sensor.TYPE_ORIENTATION);
		mPressureSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE);
		mTemperatureSensor = mSensorManager
				.getDefaultSensor(Sensor.TYPE_TEMPERATURE);
	}

	// 更新顶部方向显示的方法和中间方向值
	private void updateDirection() {
		LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
				LayoutParams.WRAP_CONTENT);
		// 先移除layout中所有的view
		mAngleLayout.removeAllViews();

		// 下面是根据mTargetDirection，显示方向
		float direction = normalizeDegree(mTargetDirection * -1.0f);
		if (direction > 22.5f && direction < 157.5f) {
			// east
			mDirectionTV.setText(R.string.direction_east);
		} else if (direction > 202.5f && direction < 337.5f) {
			// west
			mDirectionTV.setText(R.string.direction_west);
		} else {
			mDirectionTV.setText("");
		}

		if (direction > 112.5f && direction < 247.5f) {
			// south
			mDirectionTV.append(getResources().getString(
					R.string.direction_south));
		} else if (direction < 67.5 || direction > 292.5f) {
			// north
			mDirectionTV.append(getResources().getString(
					R.string.direction_north));
		} else {
			mDirectionTV.append("");
		}

		// 下面是根据方向度数显示度数图片数字
		int direction2 = (int) direction;
		boolean show = false;
		if (direction2 >= 100) {
			mAngleLayout.addView(getNumberImage(direction2 / 100));
			direction2 %= 100;
			show = true;
		}
		if (direction2 >= 10 || show) {
			mAngleLayout.addView(getNumberImage(direction2 / 10));
			direction2 %= 10;
		}
		mAngleLayout.addView(getNumberImage(direction2));
		// 下面是增加一个°的图片
		ImageView degreeImageView = new ImageView(this);
		degreeImageView.setImageResource(R.drawable.degree);
		degreeImageView.setLayoutParams(lp);
		mAngleLayout.addView(degreeImageView);
	}

	// 获取方向度数对应的图片，返回ImageView
	private ImageView getNumberImage(int number) {
		ImageView image = new ImageView(this);
		LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
				LayoutParams.WRAP_CONTENT);
		switch (number) {
		case 0:
			image.setImageResource(R.drawable.number_0);
			break;
		case 1:
			image.setImageResource(R.drawable.number_1);
			break;
		case 2:
			image.setImageResource(R.drawable.number_2);
			break;
		case 3:
			image.setImageResource(R.drawable.number_3);
			break;
		case 4:
			image.setImageResource(R.drawable.number_4);
			break;
		case 5:
			image.setImageResource(R.drawable.number_5);
			break;
		case 6:
			image.setImageResource(R.drawable.number_6);
			break;
		case 7:
			image.setImageResource(R.drawable.number_7);
			break;
		case 8:
			image.setImageResource(R.drawable.number_8);
			break;
		case 9:
			image.setImageResource(R.drawable.number_9);
			break;
		}
		image.setLayoutParams(lp);
		return image;
	}

	// 方向传感器变化监听
	private SensorEventListener mOrientationSensorEventListener = new SensorEventListener() {

		@Override
		public void onSensorChanged(SensorEvent event) {
			float direction = event.values[SensorManager.DATA_X] * -1.0f;
			mTargetDirection = normalizeDegree(direction);// 赋值给全局变量，让指南针旋转
		}

		@Override
		public void onAccuracyChanged(Sensor sensor, int accuracy) {
			// Log.i("lwp", "Sensor's accuracy = " + accuracy);
			if(!isNeedAccuracy)//只在第一次运行时校准，如果使用中出现精度不准也直接返回
				return;
			if (accuracy == SensorManager.SENSOR_STATUS_ACCURACY_LOW) {// 精度不够，需要校准
				mHandler.post(startGuideAnimTask);
			} else {
				mHandler.postDelayed(mCompassViewUpdater, 20);// 20毫秒执行一次更新指南针图片旋转
				mHandler.post(stopGuideAnimTask);
			}
		}
	};

	// 调整方向传感器获取的值
	private float normalizeDegree(float degree) {
		return (degree + 720) % 360;
	}

	BDLocationListener mLocationListener = new BDLocationListener() {

		@Override
		public void onReceivePoi(BDLocation poiLocation) {
			// do nothing
		}

		@Override
		public void onReceiveLocation(BDLocation location) {
			if (location == null) {
				Toast.makeText(CompassActivity.this,
						R.string.getting_location_fail, Toast.LENGTH_SHORT)
						.show();
				return;
			}
			mLatitudeTV.setText(getLocationString(location.getLatitude()));
			mLongitudeTV.setText(getLocationString(location.getLongitude()));
			if (location.getLocType() == BDLocation.TypeNetWorkLocation) {
				mAddressTV.setText(getResources().getString(R.string.address)
						+ location.getAddrStr());
			}
			mLocationClient.stop();
		}
	};

	// 把经纬度转换成度分秒显示
	private String getLocationString(double input) {
		if((int)input == 0)
			return "--";
		int du = (int) input;
		int fen = (((int) ((input - du) * 3600))) / 60;
		int miao = (((int) ((input - du) * 3600))) % 60;
		return String.valueOf(du) + getResources().getString(R.string.du)
				+ String.valueOf(fen) + getResources().getString(R.string.fen)
				+ String.valueOf(miao)
				+ getResources().getString(R.string.miao);
	}

	private float mPressure;
	private float mTemperature;
	private float mAltitude;
	private SensorEventListener mSensorEventListener = new SensorEventListener() {

		@Override
		public void onSensorChanged(SensorEvent event) {
			if (event.sensor.getType() == Sensor.TYPE_PRESSURE) {// 气压传感器
				float pressure = event.values[0];
				if (Math.abs(pressure - mPressure) > 10.0) {// 当变化差距大于10才更新界面，避免频繁更新
					mPressure = pressure;
					mHandler.post(mPressureUpdater);
				}
			}else if(event.sensor.getType() == Sensor.TYPE_TEMPERATURE){
				float temperture = event.values[0];
				if (Math.abs(temperture - mTemperature) > 1.0) {// 当变化差距大于10才更新界面，避免频繁更新
					mTemperature = temperture;
					mHandler.post(mTemperatureUpdater);
				}
			}
		}

		@Override
		public void onAccuracyChanged(Sensor sensor, int accuracy) {
			//do nothing
		}
	};
	// 更新气压
	protected Runnable mPressureUpdater = new Runnable() {

		@Override
		public void run() {
			Log.i("lwp", "mPressure = " + mPressure);
			mPressureTV.setText(String.format(
					getResources().getString(R.string.pressure),
					new Object[] { mPressure }));
			if (mTemperatureSensor == null) {// 如果没有温度传感器,就用默认温度值25℃
				mAltitude = (float) (18400.0F * (1.0F + 25.0F / 273.0F) * Math
						.log10(101325L / (100.0F * mPressure)));// 海拔高度
				mAltitudeTV.setText(String.format(
						getResources().getString(R.string.altitude),
						new Object[] { mAltitude }));
				return;// 计算完直接返回
			}
			if ((int) mTemperature != 0) {// 如果当前已经获得温度值
				mAltitude = (float) (18400.0F * (1.0F + mTemperature / 273.0F) * Math
						.log10(101325L / (100.0F * mPressure)));// 海拔高度
				mAltitudeTV.setText(String.format(
						getResources().getString(R.string.altitude),
						new Object[] { mAltitude }));
			}
		}
	};
	// 更新温度
	protected Runnable mTemperatureUpdater = new Runnable() {

		@Override
		public void run() {
			Log.i("lwp", "mTemperature = " + mTemperature);
			if ((int) mPressure != 0) {
				mAltitude = (float) (18400.0F * (1.0F + mTemperature / 273.0F) * Math
						.log10(101325L / (100.0F * mPressure)));// 海拔高度
				mAltitudeTV.setText(String.format(
						getResources().getString(R.string.altitude),
						new Object[] { mAltitude }));
			}
		}
	};
}
